﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System.ComponentModel;
using CoolEngine.Engine;
using System.Collections.ObjectModel;

namespace CoolEngine.Gui
{
    /// <summary>
    /// A GUI component.
    /// </summary>
    public class GuiControl : /*Component,*/ IDrawable, IUpdateable, IGameComponent
    {
        protected SpriteBatch Batch { get; private set; }
        public Rectangle DrawLocation { get; set; }
        public Vector2 TopLeft { get { return new Vector2(DrawLocation.X, DrawLocation.Y); } }
        public Vector2 BottomRight { get { return new Vector2(DrawLocation.Right, DrawLocation.Bottom); } }
        public ReadOnlyCollection<GuiControl> Controls { get { return readonlyControls; } }
        private SortedList<int, GuiControl> controls = new SortedList<int, GuiControl>();
        private SortedList<int, GuiControl> containingList;
        private ReadOnlyCollection<GuiControl> readonlyControls;
        public CoolGame Game { get; private set; }
        public GraphicsDevice GraphicsDevice { get; private set; }
        public GuiRenderer Renderer { get; private set; }
        public GuiControl Parent { get; private set; }
        public Color Tint { get; set; }
        
        private static GuiControl activeControl;
        public static GuiControl ActiveControl
        {
            get { return activeControl; }
            set
            {
                activeControl = value;
                activeControl.focus = true;
            }
        }
        private static int currentDrawOrder;
        public bool MouseVisible { get; set; }
        public bool IsInitialized { get; private set; }
        private bool focus;
        public bool HasFocus
        {
            get { return focus; }
            set
            {
                focus = value;
                if (focus)
                {
                    activeControl = this;
                }
            }
        }

        internal void BeginDraw()
        {
            GraphicsDevice.ScissorRectangle = DrawLocation;

        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        internal void EndDraw()
        {

        }
        public Vector2 GetCoordinate(Vector2 normalised)
        {
            return normalised * new Vector2(DrawLocation.Width, DrawLocation.Height) + TopLeft;
        } 
        protected virtual void InitializeComponent()
        {

        }
        public virtual void Initialize()
        {
            GraphicsDevice = Game.GraphicsDevice;
            Batch = Renderer.Batch;
            foreach (GuiControl control in Controls)
            {
                if (!control.IsInitialized)
                {
                    control.Initialize();
                }
            }
            InitializeComponent();
            IsInitialized = true;
        }
        internal void Render(GameTime gameTime)
        {
            BeginDraw();
            Draw(gameTime);
            EndDraw();
            foreach (GuiControl control in Controls)
            {
                if (control.Visible)
                {
                    control.Render(gameTime);
                }
            }

        }
        public virtual bool CaptureMouse
        {
            get { return false; }
        }
        public virtual bool CaptureKeyboard
        {
            get { return false; }
        }
        public class KeyboardInputEventArgs : EventArgs
        {
            public static readonly new KeyboardInputEventArgs Empty = new KeyboardInputEventArgs();
            public KeyboardState State { get; set; }
            public KeyboardState OldState { get; set; }
        }

        public event EventHandler<KeyboardInputEventArgs> KeyboardInput;

        public virtual void OnKeyboardInput(KeyboardInputEventArgs e)
        {
            EventHandler<KeyboardInputEventArgs> handler = KeyboardInput;
            if (handler != null)
            {
                handler(this, e);
            }
        }
        #region Mouse click
        public class MouseClickEventArgs : EventArgs
        {
            /// <summary>
            /// The normalised mouse location.
            /// </summary>
            /// <value>The location.</value>
            public Vector2 Location { get; set; }
            public MouseState MouseState { get; set; }
            public static readonly new MouseClickEventArgs Empty = new MouseClickEventArgs();
            public MouseClickEventArgs()
            {

            }
            public MouseClickEventArgs(Vector2 location, MouseState mouseState)
            {
                Location = location;
                MouseState = mouseState;
            }
        }

        public event EventHandler<MouseClickEventArgs> MouseClick;

        public virtual void OnMouseClick(MouseClickEventArgs e)
        {
            EventHandler<MouseClickEventArgs> handler = MouseClick;
            if (handler != null)
            {
                handler(this, e);
            }
        }
        #endregion
        #region Constructors
        public GuiControl(CoolGame game, GuiRenderer renderer, GuiControl parent)
        {
            Parent = parent;
            DrawLocation = new Rectangle(0, 0, 1, 1);
            drawOrder = currentDrawOrder++;
            if (parent != null)
            {
                parent.controls.Add(DrawOrder, this);
                containingList = parent.controls;
            }
            if (game != null)
            {

                Game = game;
                GraphicsDevice = game.GraphicsDevice;
            }
            if (renderer != null)
            {
                Renderer = renderer;
                if (parent == null)
                {
                    renderer.AddControl(this);
                }
                containingList = Renderer.controls;
            }
            Tint = Color.White;
            readonlyControls = new ReadOnlyCollection<GuiControl>(controls.Values);
        }
        public GuiControl(CoolGame game, GuiRenderer renderer)
            : this(game, renderer, null)
        {

        }
        //public GuiControl()
        //    : this(GameManager.Game, GameManager.GuiRenderer)
        //{

        //}
        #endregion
        #region IUpdateable Members

        public virtual bool Enabled
        {
            get { return enabled; }
            set
            {
                enabled = value;
                OnEnabledChanged(this, EventArgs.Empty);
            }
        }
        private bool enabled = true;
        public event EventHandler EnabledChanged;

        public virtual void Update(GameTime gameTime)
        {
            foreach (GuiControl control in Controls)
            {
                control.Update(gameTime);
            }
        }

        public int UpdateOrder
        {
            get { return updateOrder; }
            set
            {
                updateOrder = value;
                EventHandler temp = UpdateOrderChanged;
                if (temp != null)
                {
                    temp(this, EventArgs.Empty);
                }
            }
        }
        private int updateOrder;
        public event EventHandler UpdateOrderChanged;
        protected virtual void OnEnabledChanged(object sender, EventArgs e)
        {
            EventHandler temp = EnabledChanged;
            if (temp != null)
            {
                temp(sender, e);
            }
        }
        private bool visible;
        public bool Visible
        {
            get { return visible; }
            set
            {
                visible = value;
                OnVisibleChanged(this, EventArgs.Empty);
                if (this is GameScreen)
                {

                }
            }
        }
        public event EventHandler VisibleChanged;
        protected virtual void OnVisibleChanged(object guiComponent, EventArgs eventArgs)
        {
            EventHandler temp = VisibleChanged;
            if (temp != null)
            {
                temp(guiComponent, eventArgs);
            }
        }
        #endregion
        #region IDrawable Members

        public virtual void Draw(GameTime gameTime)
        {

        }
        private int drawOrder;
        public int DrawOrder
        {
            get { return drawOrder; }
            set
            {
                containingList.Remove(drawOrder);
                drawOrder = value;
                containingList.Add(value, this);
                if (DrawOrderChanged != null)
                {
                    DrawOrderChanged(this, EventArgs.Empty);
                }
            }
        }
        public event EventHandler DrawOrderChanged;
        #endregion
    }
}
